"""Settings registry for KikoTools.

This module provides a centralized settings management system for all KikoTools.
Tools can register their settings, which are then exposed in ComfyUI's settings UI.
"""

import json
import os
from typing import Dict, Any, List, Optional, Union
from dataclasses import dataclass, field


@dataclass
class SettingDefinition:
    """Definition of a single setting."""

    id: str
    name: str
    type: str  # "boolean", "combo", "number", "string", "custom"
    default: Any
    description: Optional[str] = None
    options: Optional[Union[List[Any], Dict[str, Any]]] = None
    min_value: Optional[float] = None
    max_value: Optional[float] = None
    step: Optional[float] = None
    on_change: Optional[str] = None  # JavaScript callback as string


@dataclass
class ToolSettings:
    """Settings collection for a single tool."""

    tool_name: str
    display_name: str
    settings: List[SettingDefinition] = field(default_factory=list)


class SettingsRegistry:
    """Central registry for all KikoTools settings."""

    def __init__(self):
        self.tools: Dict[str, ToolSettings] = {}
        self.settings_by_id: Dict[str, SettingDefinition] = {}

    def register_tool_settings(
        self, tool_name: str, display_name: str, settings: Dict[str, Dict[str, Any]]
    ) -> None:
        """Register settings for a tool.

        Args:
            tool_name: Internal tool identifier (e.g., "embedding_autocomplete")
            display_name: Display name for the tool (e.g., "Embedding Autocomplete")
            settings: Dictionary of setting configurations
                {
                    "enabled": {
                        "type": "boolean",
                        "default": True,
                        "description": "Enable embedding autocomplete"
                    },
                    "max_suggestions": {
                        "type": "combo",
                        "default": 20,
                        "options": [10, 20, 50],
                        "description": "Maximum number of suggestions"
                    }
                }
        """
        tool_settings = ToolSettings(tool_name, display_name)

        for setting_key, config in settings.items():
            # Generate fully qualified setting ID
            setting_id = f"kikotools.{tool_name}.{setting_key}"

            # Create display name with branding
            setting_name = f"🫶 {display_name}: {setting_key.replace('_', ' ').title()}"

            setting_def = SettingDefinition(
                id=setting_id,
                name=setting_name,
                type=config.get("type", "string"),
                default=config.get("default"),
                description=config.get("description"),
                options=config.get("options"),
                min_value=config.get("min"),
                max_value=config.get("max"),
                step=config.get("step"),
                on_change=config.get("on_change"),
            )

            tool_settings.settings.append(setting_def)
            self.settings_by_id[setting_id] = setting_def

        self.tools[tool_name] = tool_settings

    def get_setting(self, setting_id: str) -> Optional[SettingDefinition]:
        """Get a setting definition by ID."""
        return self.settings_by_id.get(setting_id)

    def get_tool_settings(self, tool_name: str) -> Optional[ToolSettings]:
        """Get all settings for a tool."""
        return self.tools.get(tool_name)

    def generate_frontend_registration(self) -> str:
        """Generate JavaScript code for frontend settings registration."""
        js_lines = [
            "// Auto-generated KikoTools settings registration",
            "// This file is automatically generated by the settings registry",
            "",
            "import { app } from '../../scripts/app.js';",
            "",
            "app.registerExtension({",
            "    name: 'kikotools.settings',",
            "    async init() {",
            "        // Register all KikoTools settings",
        ]

        for tool_name, tool_settings in self.tools.items():
            js_lines.append(f"        // {tool_settings.display_name} settings")

            for setting in tool_settings.settings:
                js_lines.append("        app.ui.settings.addSetting({")
                js_lines.append(f'            id: "{setting.id}",')
                js_lines.append(f'            name: "{setting.name}",')
                js_lines.append(
                    f"            defaultValue: {self._js_value(setting.default)},"
                )
                js_lines.append(f'            type: "{setting.type}",')

                if setting.description:
                    js_lines.append(f'            tooltip: "{setting.description}",')

                if setting.type == "combo" and setting.options:
                    js_lines.append("            options: (value) => {")
                    js_lines.append(
                        f"                const options = {json.dumps(setting.options)};"
                    )
                    js_lines.append("                return options.map(opt => ({")
                    js_lines.append("                    value: opt,")
                    js_lines.append("                    text: String(opt),")
                    js_lines.append("                    selected: opt === value")
                    js_lines.append("                }));")
                    js_lines.append("            }},")

                if setting.type == "number":
                    if setting.min_value is not None:
                        js_lines.append(f"            min: {setting.min_value},")
                    if setting.max_value is not None:
                        js_lines.append(f"            max: {setting.max_value},")
                    if setting.step is not None:
                        js_lines.append(f"            step: {setting.step},")

                if setting.on_change:
                    js_lines.append("            onChange(value) {")
                    js_lines.append(f"                {setting.on_change}")
                    js_lines.append("            }")

                js_lines.append("        }});")
                js_lines.append("")

        js_lines.extend(["    }", "});", ""])

        return "\n".join(js_lines)

    def _js_value(self, value: Any) -> str:
        """Convert Python value to JavaScript literal."""
        if isinstance(value, bool):
            return "true" if value else "false"
        elif isinstance(value, str):
            return f'"{value}"'
        elif value is None:
            return "null"
        else:
            return str(value)

    def save_frontend_settings(
        self, output_path: str = "web/js/kikoSettings.js"
    ) -> None:
        """Save the generated frontend settings to a file."""
        js_content = self.generate_frontend_registration()

        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        with open(output_path, "w") as f:
            f.write(js_content)

    def get_all_settings(self) -> Dict[str, Any]:
        """Get all registered settings as a dictionary."""
        result = {}
        for tool_name, tool_settings in self.tools.items():
            result[tool_name] = {
                "display_name": tool_settings.display_name,
                "settings": {
                    setting.id.split(".")[-1]: {
                        "type": setting.type,
                        "default": setting.default,
                        "description": setting.description,
                        "options": setting.options,
                    }
                    for setting in tool_settings.settings
                },
            }
        return result
